package com.yq.tanhua.net

import ApiException
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import javax.net.ssl.SSLHandshakeException

typealias Block<T> = suspend (CoroutineScope) -> T
typealias Error = suspend (ApiException) -> Unit
typealias Cancel = suspend (Exception) -> Unit
typealias NetErr = suspend (Exception) -> Unit

open class BaseViewModel : ViewModel() {

    /**
     * 创建并执行协程任务
     * @param block 协程任务执行
     * @param error 执行过程中的异常执行
     * @param cancel 协程任务取消时执行
     */
    protected fun launch(
        block: Block<Unit>,
        error: Error? = null,
        cancel: Cancel? = null,
        netErr: NetErr? = null
    ): Job {
        return viewModelScope.launch {
            try {
                block.invoke(this)
            } catch (e: Exception) {
                when (e) {
                    is CancellationException -> {
                        cancel?.invoke(e)
                    }
                    is ApiException -> {
                        error?.invoke(e)
                    }
                    is HttpException -> {
                        var msg = e.response()?.errorBody()?.string()
                        val apiException =
                            ApiException(1000, if (msg == null) e.message() else msg!!)
                        error?.invoke(apiException)
                    }
                    else -> {
                        val apiException =
                            ApiException(1000, if (e.message == null) "" else e.message!!)
                        error?.invoke(apiException)
                    }
                }
            }
        }
    }

    /**
     *统一异常处理
     * @param e 异常
     */
    private suspend fun onError(e: Exception, error: NetErr?) {
        when (e) {
            // 网络请求失败
            is ConnectException,
            is SocketTimeoutException,
            is UnknownHostException,
            is HttpException,
            is SocketException,
            is SSLHandshakeException -> {
                error?.invoke(e)
            }
            else -> {
                error?.invoke(e)
            }
        }
    }

    /**
     *执行协程异步任务
     */
    protected fun <T> async(block: Block<T>): Deferred<T> {
        return viewModelScope.async { block.invoke(this) }
    }

    /**
     * 取消执行
     */
    protected fun cancelJob(job: Job?) {
        if (job != null && job.isActive && !job.isCompleted && !job.isCancelled) {
            job.cancel()
        }
    }
}